#! /usr/bin/env python
# coding=utf-8
#############################################################################
#                                                                           #
#   File: listfiles.py                                                      #
#                                                                           #
#   Copyright (C) 2008 Chen Baiping <chenbaiping@21cn.com>                  #
#                                                                           #
#   This program is free software; you can redistribute it and/or modify    #
#   it under the terms of the GNU General Public License as published by    #
#   the Free Software Foundation; either version 2 of the License, or       #
#   (at your option) any later version.                                     #
#                                                                           #
#   Home: http://enter.appspot.com                                          #
#                                                                           #
#############################################################################
import wsgiref.handlers
import urlparse
import StringIO
import logging
import base64
import zlib 
import gzip 
import tarfile 
import re
import traceback
import os
import sys
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.api import urlfetch
from google.appengine.api import memcache
from google.appengine.ext.webapp import template

import codecs, sys, StringIO
 
ROOT_DIR='.'

def tarPath( root, name, tfile ):
    '''root:a directory; name: entry in root, tfile: tarfile object.
    '''
    info = tarfile.TarInfo()
    if root:
        path=root+'/'+name
    else:
        path=name
    if os.path.isdir(path):
        entries = os.listdir(path) 
        for entry in entries:
            fullPath = path+'/'+entry
            if os.path.isdir(fullPath): 
                info.size =0
                info.name=fullPath
                info.type=tarfile.DIRTYPE
                tfile.addfile( info  )
                tarPath('', fullPath, tfile )
            else: # is file
                f=file(fullPath,'rb')
                info.type=tarfile.REGTYPE
                info.size =os.path.getsize(fullPath);
                info.name=fullPath
                info.mtime=os.path.getmtime(fullPath);
                tfile.addfile( info, f )


def gztarfile( path ):
    '''Archive and zip all files and directories under the special path.    
    '''
    tarbuf = StringIO.StringIO()
    tar=tarfile.TarFile(mode='w',fileobj=tarbuf)
    #tar.add(path)
    tarPath( '',path, tar )
    tar.close()
    zbuf=StringIO.StringIO() 
    zfile=gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=9)
    zfile.write(tarbuf.getvalue())
    zfile.close() 
    return zbuf.getvalue()  

class MainFrame(webapp.RequestHandler):  
    def get(self):      
        html=''' 
    <HTML><head>
    <TITLE> GAE App Files Browser </TITLE>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<FRAMESET ROWS="," COLS="30%,70%" bordercolor="#ffdddd">
    <FRAME SRC="/static/tree.html" NAME="list" target='file'>
    <FRAME SRC="/static/file.html" NAME="file">
</FRAMESET>
    <BODY>
    </BODY>
    </HTML>'''
        self.response.out.write(html)   
        
#a global counter, for tree xml element's id.        
itemCount=0

def listPath(root, name, outXmlStringIO ):
    '''iterate all directies and files , name is directory name or file name
    '''
    global itemCount
    if root:
        path=root+'/'+name
    else:
        path=name
#    print root, name 
    if os.path.isdir(path):
        entries = os.listdir(path)
        #First, list all directories 
        for entry in entries:
            fullPath = path+'/'+entry
            if os.path.isdir(fullPath):#            <item text="My Computer" id="1" child="1"
                itemCount =1 +itemCount
                countFiles=len(os.listdir(fullPath))
                if countFiles>0:
#                    logging.info(fullPath)
#                    logging.info(countFiles)
                    text=entry + " <a href='/listfiles/file?op=download&fn=" + fullPath+ "' >[D]</a> "
                    text = text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
                    outXmlStringIO.write( '<item text="'+text+'" id="dir_'+str(itemCount)+'" child="1" count="' \
                                          +str(countFiles)+'"   >'   ) 
                else:
                    outXmlStringIO.write( '<item text="'+entry+'" id="dir_'+str(itemCount)+'" child="1" im0="folderClosed.gif" >'   ) 
                
                listPath(path, entry, outXmlStringIO )
                outXmlStringIO.write( '</item>'   ) 
                outXmlStringIO.write( '\r\n'   ) 
                
        for entry in entries:  
            fullPath = path+'/'+entry
            if os.path.isfile(fullPath):
                itemCount =1 +itemCount
                fullPath = path+'/'+entry
                text=" <a href='/listfiles/file?op=view&fn="+ fullPath+"' target='file'>"+entry + "</a> " \
                    +" <a href='/listfiles/file?op=download&fn="+ fullPath+"' >[D]</a> " 
                text = text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
                item='<item id="file_'+str(itemCount)+'" text="'+text+'" child="1"   >  </item> '
                outXmlStringIO.write( item )
                outXmlStringIO.write( '\r\n' )
     
#                <item id="123">  <itemtext><![CDATA[<font color="red">Label</font>]]></itemtext> </item> 
#def listDir( dir ):
#    outXml = StringIO.StringIO()
#    listPath( '',ROOT_DIR,outXml )
#    return outXml.getvalue()
#              
       
class MainListXML(webapp.RequestHandler):  
    def get(self):  
        outXml = StringIO.StringIO()
        listPath( '', ROOT_DIR, outXml )  
        dir = os.path.dirname(__file__);
        app_name = dir[dir.find('apps')+5:].replace('/','_')
        text= app_name+ " <a href='/listfiles/file?op=download&fn=.' >[D]</a> "
        text = text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;') 
 
        self.response.headers[ 'Content-type'] = 'text/xml;charset=utf-8'         
        self.response.out.write('''<?xml version='1.0' encoding='iso-8859-1'?>
<tree id="0">
<item text="'''+text+'''" id="approot" child="1" im0="folderClosed.gif" open="1" >
''')
        self.response.out.write(outXml.getvalue())  
        self.response.out.write('</item> ')  
        self.response.out.write('</tree> ')  

        
class MainFile(webapp.RequestHandler):  
    def get(self):       
        unicode_fn= self.request.get('fn')
        fn = unicode_fn.encode('ascii', 'ignore')
        filename=fn
        
        iLastSlash = fn.rfind('/')
        if iLastSlash>=0:
            filename=fn[iLastSlash+1:]
        fullpath=ROOT_DIR+'/'+fn
#        self.response.out.write('get file=' + filename) 
#        return
        if fullpath.find('./')==0:
            fullpath=fullpath[2:]
        if fullpath.find('./')==0:
            fullpath=fullpath[2:]
        logging.info(' fn='+fullpath)
            
        if os.path.isfile( fullpath ):                
#            logginginfol('222222  fn='+fullpath)             
            if self.request.get('op')=='view':
                logging.info('view='+fullpath)
                if re.match('.*\.gif$', fn, re.IGNORECASE) :
                    self.response.headers[ 'Content-Type'] = 'image/gif' 
                elif re.match('.*\.jpe?g$', fn, re.IGNORECASE) :
                    self.response.headers[ 'Content-Type'] = 'image/jpeg' 
#                    logging.info(self.response.headers[ 'Content-Type'])
                elif re.match('.*\.bmp$', fn, re.IGNORECASE) :
                    self.response.headers[ 'Content-Type'] = 'image/x-ms-bmp' 
                elif re.match('.*\.png$', fn, re.IGNORECASE) :
                    self.response.headers[ 'Content-Type'] = 'image/x-png' 
                elif re.match('.*\.tiff?$', fn, re.IGNORECASE) :
                    self.response.headers[ 'Content-Type'] = 'image/tiff' 
                else:
                    self.response.headers[ 'Content-Type'] = 'text/plain' 
            else:
                logging.info('download='+fullpath)                  
                self.response.headers[ 'Content-Type'] = 'application/octet-stream' 
                self.response.headers[ "Content-Disposition"]= "attachment;filename="+filename; 
            #a file
            f = open( fullpath, 'rb')
            while True:
                buf = f.read(1<<20) #1M, file length exceed 1M will be truncat by GAE.
                if buf:
                    self.response.out.write(buf)  
                else: 
                    break
#            for line in f:
#                self.response.out.write(line)   
#            f.close()
        elif os.path.isdir( fullpath ):
#            logging.info('333333  fn='+fullpath)            
            #a directory
            if filename=='.':
                dir = os.path.dirname(__file__);
                filename = dir[dir.find('apps')+5:].replace(os.sep,'_')  
#                filename='app'
            self.response.headers[ 'Content-Type'] = 'application/octet-stream'  
#            logging.info( self.response.headers[ 'Content-Type'])
            self.response.headers.add_header( 'Content-Type', 'application/zip' )
            self.response.headers[ "Content-Disposition" ]= "attachment;filename="+ filename+'.tar.gz';

            self.response.out.write(gztarfile(fullpath) )  

        else:            
#            logging.info('4444  fn='+fullpath)
            self.response.out.write('No such file=' + fullpath)  
            

def main():
    application = webapp.WSGIApplication([ 
                                          (r'/listfiles/list', MainListXML),  
                                          ('/listfiles/file', MainFile),  
                                          ('/listfiles/frame', MainFrame),   
                                          ('/listfiles.*', MainFrame), 
                                          ], debug=True)
    wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
    main()
